package com.testdocs.client.version.list;

import java.util.List;
import java.util.Set;

import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.testdocs.client.common.dialog.confirm.ConfirmDialog;
import com.testdocs.client.common.i18n.CommonConstants;
import com.testdocs.client.style.TableResources;
import com.testdocs.client.validation.ConstraintViolationException;
import com.testdocs.client.validation.ValidationConstraint;
import com.testdocs.client.version.VersionInfo;
import com.testdocs.client.version.i18n.VersionConstants;
import com.testdocs.client.version.i18n.VersionMessages;
import com.testdocs.client.version.list.add.NewVersionDialog;
import com.testdocs.client.version.list.add.NewVersionDialog.ActionConfirmedHandler;
import com.testdocs.client.version.list.rename.RenameVersionDialog;

public class VersionListViewImpl extends Composite implements VersionListView {
	@UiTemplate("VersionList.ui.xml")
	interface VersionListViewUiBinder extends
			UiBinder<Widget, VersionListViewImpl> {
	}

	private static VersionListViewUiBinder uiBinder = GWT
			.create(VersionListViewUiBinder.class);

	@UiField
	Label versionsLabel;
	@UiField(provided = true)
	CellTable<VersionInfo> cellTable;
	@UiField
	SimplePager pager;

	@UiField
	Button createButton;
	@UiField
	Button renameButton;
	@UiField
	Button removeButton;

	@UiField(provided=true)
	Anchor selectAllAnchor;
	@UiField(provided=true)
	Anchor selectNoneAnchor;

	@UiFactory
	SimplePager getPager() {
		pager = new SimplePager();
		pager.setDisplay(cellTable);
		return pager;
	}

	ListDataProvider<VersionInfo> dataProvider = new ListDataProvider<VersionInfo>();
	MultiSelectionModel<VersionInfo> selectionModel = new MultiSelectionModel<VersionInfo>();

	private NewVersionDialog newVersionDialog = new NewVersionDialog();
	private ConfirmDialog confirmDialog = new ConfirmDialog();
	private RenameVersionDialog renameDialog = new RenameVersionDialog();

	private VersionConstants versionConstants = (VersionConstants) GWT
			.create(VersionConstants.class);
	private VersionMessages versionMessages = (VersionMessages) GWT
			.create(VersionMessages.class);
	private CommonConstants commonConstants = (CommonConstants) GWT
			.create(CommonConstants.class);

	private Presenter presenter;

	public VersionListViewImpl() {
		TableResources resources = GWT.create(TableResources.class);		
		cellTable = new CellTable<VersionInfo>(15, resources);
		selectAllAnchor = new Anchor(commonConstants.selectAll(), false);
		selectNoneAnchor = new Anchor(commonConstants.selectNone(), false);

		initWidget(uiBinder.createAndBindUi(this));

		versionsLabel.setText(versionConstants.versionsLabel());
		createButton.setText(versionConstants.create());
		removeButton.setText(versionConstants.remove());
		renameButton.setText(versionConstants.rename());

		dataProvider.addDataDisplay(cellTable);
		renameButton.setEnabled(false);
		removeButton.setEnabled(false);
		initTableColumns();

		cellTable.addColumnStyleName(0, resources.cellTableStyle().checkboxCell());

		// Add a selection model to handle user selection.
		selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			public void onSelectionChange(SelectionChangeEvent event) {
				Set<VersionInfo> selectedSet = selectionModel.getSelectedSet();
				if (selectedSet.size() == 1) {
					renameButton.setEnabled(true);
				} else {
					renameButton.setEnabled(false);
				}
				
				if (selectedSet.size() == 0
						|| selectedSet.size() == dataProvider.getList().size()) {
					removeButton.setEnabled(false);
				} else {
					removeButton.setEnabled(true);
				}
			}
		});
	}

	@Override
	public void setPresenter(Presenter presenter) {
		this.presenter = presenter;
	}

	private void initTableColumns() {
		Column<VersionInfo, Boolean> checkColumn = new Column<VersionInfo, Boolean>(
				new CheckboxCell(true, true)) {
			@Override
			public Boolean getValue(VersionInfo object) {
				// Get the value from the selection model.
				return selectionModel.isSelected(object);
			}
		};
		checkColumn.setFieldUpdater(new FieldUpdater<VersionInfo, Boolean>() {
			public void update(int index, VersionInfo object, Boolean value) {
				// Called when the user clicks on a checkbox.
				selectionModel.setSelected(object, value);
			}
		});
		cellTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br>"));

		// Version column
		Column<VersionInfo, String> nameColumn = new Column<VersionInfo, String>(
				new TextCell()) {
			@Override
			public String getValue(VersionInfo object) {
				return object.getName();
			}
		};
		cellTable.addColumn(nameColumn, versionConstants.versionColumn());
	}

	@UiHandler("createButton")
	void handleCreateClick(ClickEvent e) {
		newVersionDialog.show(dataProvider.getList(),
				new ActionConfirmedHandler() {
					@Override
					public void handle(String name, String basedOnVersionId) throws ConstraintViolationException {
						VersionInfo newVersionInfo = new VersionInfo();
						newVersionInfo.setName(name);
						ValidationConstraint constraints[] = newVersionInfo.selfValidate();
						if (constraints != null) {
							throw new ConstraintViolationException(constraints);
						}

						List<VersionInfo> versionsList = dataProvider.getList();
						int index = 0;
						for (VersionInfo v : versionsList) {
							if (v.getId().equals(basedOnVersionId)) {
								break;
							}
							index++;
						}
						dataProvider.getList().add(index, newVersionInfo);
						presenter.saveNewVersion(newVersionInfo, basedOnVersionId);
						applySelectionToAll(false);
					}
				});
	}

	@UiHandler("renameButton")
	void handleRenameClick(ClickEvent e) {
		rename((VersionInfo) selectionModel.getSelectedSet().toArray()[0]);
	}

	@UiHandler("removeButton")
	void handleRemoveClick(ClickEvent e) {
		Set<VersionInfo> selectedSet = selectionModel.getSelectedSet();
		remove(selectedSet);
	}

	@UiHandler("selectAllAnchor")
	void handleSelectAllClick(ClickEvent e) {
		applySelectionToAll(true);
	}

	@UiHandler("selectNoneAnchor")
	void handleSelectNoneClick(ClickEvent e) {
		applySelectionToAll(false);
	}

	void applySelectionToAll(boolean value) {
		for (VersionInfo versionInfo : dataProvider.getList()) {
			selectionModel.setSelected(versionInfo, value);
		}
		cellTable.redraw();
	}
	
	@Override
	public void setVersionsList(VersionInfo[] versions) {
		List<VersionInfo> versionsList = dataProvider.getList();
		versionsList.clear();
		for (VersionInfo version : versions) {
			versionsList.add(version);
		}
	}

	@Override
	public void setSavedVersion(VersionInfo versionInfoToReplace,
			VersionInfo savedVersionInfo) {
		List<VersionInfo> versionsList = dataProvider.getList();
		versionsList.set(versionsList.indexOf(versionInfoToReplace),
				savedVersionInfo);
		dataProvider.flush();
	}

	public void rename(final VersionInfo versionInfo) {
		renameDialog.show(versionInfo.getName(),
				new RenameVersionDialog.ActionConfirmedHandler() {
					@Override
					public void handle(String name) throws ConstraintViolationException {
						if (!name.equals(versionInfo.getName())) {
							versionInfo.setName(name);							
							presenter.rename(versionInfo);
							dataProvider.refresh();
						}
					}
				});
	}

	public void remove(final Set<VersionInfo> versions) {
		confirmDialog.show(versionConstants.remove(), versionMessages
				.removeConfirmation(versions.size()),
				new ConfirmDialog.ActionConfirmedHandler() {
					@Override
					public void handle() {
						dataProvider.getList().removeAll(versions);
						VersionInfo[] versionsArray = new VersionInfo[versions.size()];
						presenter.remove(versions.toArray(versionsArray));
						for (VersionInfo versionInfo : versions) {
							selectionModel.setSelected(versionInfo, false);
						}
						dataProvider.flush();
						dataProvider.refresh();
					}
				});
	}
}
